package com.hsc.mvc.tag;

import com.hsc.mvc.util.StringUtil;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * @author
 * @date 2025-05-18
 * @Description
 */
public class AopMappingTag {
    private String classStr;
    // 由于url 是多个 所以使用set集合
    //  "/test1.do,/test2.do,/test3.do"
    /**
     * * 切面信息中的include和exclude都可以包含多个请求
     *
     * * 配置时使用逗号分隔
     *
     * * 存储时将其以set集合存储
     */
    private Set<String> include;
    /**
     * * 切面信息中的include和exclude都可以包含多个请求
     *
     * * 配置时使用逗号分隔
     *
     * * 存储时将其以set集合存储
     */
    private Set<String> exclude;
    private Class aopClass;

    public AopMappingTag() {
    }

    public String getClassStr() {
        return classStr;
    }

    public void setClassStr(String classStr) {
        // 设置Class对象
        this.classStr = classStr;
        try {
            Class<?> aopClass = Class.forName(classStr);
            setAopClass(aopClass);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public Set<String> getInclude() {
        return include;
    }

    public void setInclude(String include) {
        if (StringUtil.isEmpty(include)) {
            return;
        }
        String[] url = include.split(",");
        Set<String> includeUrlSet = new HashSet<>(Arrays.asList(url));
        this.include = includeUrlSet;

    }

    public Set<String> getExclude() {
        return exclude;
    }

    public void setExclude(String exclude) {
        if (StringUtil.isEmpty(exclude)) {
            return;
        }
        String[] url = exclude.split(",");
        Set<String> exCludeUrlSet = new HashSet<>(Arrays.asList(url));
        this.exclude = exCludeUrlSet;
    }

    public Class getAopClass() {
        return aopClass;
    }

    public void setAopClass(Class aopClass) {
        this.aopClass = aopClass;
    }


    /**
     * 判断当前的拦截是否支持指定的请求 排查过程
     * 1、先判断include(进行拦截)  2、再判断exclude（排除）
     * @param requestURI
     * @return
     */
    public boolean isSupport(String requestURI) {
        // 初始值 false
        boolean flag = false;
        // 1、如果 include 为空  直接无须拦截
        if (include==null || include.size()==0) {
            return false;
        }

        // 2、 先判断include  中是否满足要求
        // 遍历判断
        for (String include : include) {
            if ((flag=isSupportTemplate(requestURI,include))){
                // 如果include 中符合拦截规则  b 返回 true 直接跳出循环
                break;
            }
        }
        if (!flag){
            //include不包含 所以flag为false。 说明不进行拦截 直接返回false 了
            // 就不在考虑exclude问题
            return false;
        }
        //如果exclude 没有放行的配置  直接不用判断
        if (exclude==null || exclude.size()==0) {
            // 走到这里 flag为 true
            return true;
        }
        // 代码走到这里 说明当前的拦截器的url 是匹配进来的uri的
        // flag为 true
        // 但是只满足一项还不行  如果exclude 进行了排除 表示不进行拦截
        // 所以当前的拦截器还是对uri 进行放行
        // 所以我们初始化标识为false
        flag=false;
        // 3、再判断exclude  中是否排除
        for (String ex : exclude) {
            // 注意 ： 这里flag 返回ture 说明是放行的
            if ((flag=isSupportTemplate(requestURI,ex))){
                // 找到了一个 放行的满足 直接跳出循环
                break;
            }
        }
        // 走到这里 如果flag 为true  说明匹配到放行的uri  说明当前拦截器还是进行放行 我们的结果最终结果 返回false  说明当的拦截器 不进行拦截
        // 如果为 false的话 为前面的初始化的值    flag=false; 说明我们的exclude 中没有匹配的 我们需要对当前的uri进行拦截 需要返回 true
        return !flag;
    }

    private boolean isSupportTemplate(String requestURI, String include) {
        //1、判断是否完全等值  比如 include  配置  /test   requestURI也为 /test
        if (requestURI.equals(include)){
            return true;
        }
        //2、判断是否全局匹配拦截 比如 include 为/*  表示拦截所有
        if (include.equals("/*")){
            return true;
        }
        // 3、 判断include 结尾为 /* 结尾的 这样的情况 比如：/user/* , /user/a/*
        if (include.endsWith("/*")){
            //此时就是检测请求的name是不是/user/前缀
            //include=/user/* , request.name=/user/add.do
            // /user/ , /user/a/
            String prefix = include.replace("*", "");
            if (requestURI.startsWith(prefix)){
                return true;
            }
        }
        // 4、第四种情况  比如 写的通配符为 *.do
        if(include.startsWith("*.")){
            //此判断成立，说明一定是这类配置  *.do , *.action , *.html
            String suffix = include.replace("*.", "");
            //此时就是检测请求的name是不是 .do后缀
            //.do , .html , .jsp
            if (requestURI.endsWith(suffix)){
                return true;
            }
        }
        // 如果以上都不满足 说明当前拦截器  不对 该uri 的路径进行拦截
        // 返回 false
        return  false;

    }





}
